
#include "VxIrrLib.h"

#include <VxUtilLib/VxColorUtil.h>

//------------------------------------------------------------------------------
//=== constructor ===//
EntEarth::EntEarth( VxIrrBase * poIrrBase, const EntSpawnData& oEntSpawnData )
	: EntBase( poIrrBase )
	, m_iDefautCraterIdx(0)
	, m_iSizzelCnt(0)			// number of times comet went into water
	, m_iImpactCnt(0)			// number of times comet impacted earth
{
	log_msg( 0, "EntEarth::EntEarth: creating entity\n" );

	SetEntType( eEntityTypeEarth );
	if( poIrrBase->m_iScnSizeX > 400 )
	{
		CreateEntity( oEntSpawnData, 1.15f );
	}
	else
	{
		CreateEntity( oEntSpawnData, 1.0f );
	}
	if( m_poSceneNode )
	{
		// add animator to rotate the earth
		irr::scene::ISceneNodeAnimator* anim;
		switch( m_poIrrBase->m_iGameLevel )
		{
		case 3:
			anim = poIrrBase->m_poSceneMgr->createRotationAnimator(irr::core::vector3df(0,0.55f,0));
			break;
		case 2:
			anim = poIrrBase->m_poSceneMgr->createRotationAnimator(irr::core::vector3df(0,0.28f,0));
			break;
		default:
			anim = poIrrBase->m_poSceneMgr->createRotationAnimator(irr::core::vector3df(0,0.2f,0));
			break;
		}
		m_poSceneNode->addAnimator(anim);
		anim->drop();
	}
	// Add the billboard. used for pointing
//	m_poPointBillboard = poIrrBase->m_poSceneMgr->addBillboardSceneNode();
//	m_poPointBillboard->setMaterialType( irr::video::EMT_TRANSPARENT_ADD_COLOR );
//	m_poPointBillboard->setMaterialTexture(0, poIrrBase->m_poDriver->getTexture( GetAssetPathAndName( "particle.png", eGameAssetTypeTexture ) ));
//	m_poPointBillboard->setMaterialFlag(irr::video::EMF_LIGHTING, false);
//	m_poPointBillboard->setMaterialFlag(irr::video::EMF_ZBUFFER, false);
//	m_poPointBillboard->setSize(irr::core::dimension2d<irr::f32>(20.0f, 20.0f));
//	m_poPointBillboard->setID(-1); // This ensures that we don't accidentally ray-pick it

}

//------------------------------------------------------------------------------
//=== methods ===//
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//! override EntBase
//! load and apply textures from template
RCODE   EntEarth::ApplyTextures( EntTemplate * poEntTemplate )
{
	// we want to make sure the earth texture is 32 bit.. also the crater
	// this makes the crater damage image drawing much simpler
	irr::core::stringc strFileName;
	if( poEntTemplate->m_astrTextures[0] != "" )
	{
		strFileName = GetAssetPathAndName( poEntTemplate->m_astrTextures[0].c_str(), eGameAssetTypeTexture );
		irr::video::ITexture * poTexture = getARGBTexture( m_poIrrBase->m_poDriver, strFileName );
		m_poSceneNode->setMaterialTexture(0, poTexture );
		m_poSceneNode->setMaterialFlag(irr::video::EMF_LIGHTING, false);
	}
	return LoadCrater();
}
//------------------------------------------------------------------------------
//! load image of crater to draw on earth when impacted
RCODE   EntEarth::LoadCrater( void )
{
	irr::core::stringc strFileName;
	strFileName = GetAssetPathAndName( "Crater0.png", eGameAssetTypeTexture );
	m_apoTexCraters[0] = getARGBTexture( m_poIrrBase->m_poDriver, strFileName.c_str() );
	vx_assert( m_apoTexCraters[0] );

	strFileName = GetAssetPathAndName( "Crater1.png", eGameAssetTypeTexture );
	m_apoTexCraters[1] = getARGBTexture( m_poIrrBase->m_poDriver, strFileName.c_str() );
	vx_assert( m_apoTexCraters[1] );

	strFileName = GetAssetPathAndName( "Crater2.png", eGameAssetTypeTexture );
	m_apoTexCraters[2] = getARGBTexture( m_poIrrBase->m_poDriver, strFileName.c_str() );
	vx_assert( m_apoTexCraters[2] );

	strFileName = GetAssetPathAndName( "Crater3.png", eGameAssetTypeTexture );
	m_apoTexCraters[3] = getARGBTexture( m_poIrrBase->m_poDriver, strFileName.c_str() );
	vx_assert( m_apoTexCraters[3] );

	switch( m_poIrrBase->m_iGameLevel )
	{
	case 3:
		m_iDefautCraterIdx	= 3;
		m_poTexDefaultCrater = m_apoTexCraters[3];	// default crater for selected level
		m_poTexCurCrater = m_apoTexCraters[3];		// crater to use currently.. power ups may change this to larger crater
		break;
	case 2:
		m_iDefautCraterIdx	= 2;
		m_poTexDefaultCrater = m_apoTexCraters[2];	// default crater for selected level
		m_poTexCurCrater = m_apoTexCraters[2];		// crater to use currently.. power ups may change this to larger crater
		break;
	case 1:
	default:
		m_iDefautCraterIdx	= 1;
		m_poTexDefaultCrater = m_apoTexCraters[1];	// default crater for selected level
		m_poTexCurCrater = m_apoTexCraters[1];		// crater to use currently.. power ups may change this to larger crater
		break;
	}
	strFileName = GetAssetPathAndName( "continents.png", eGameAssetTypeTexture );
	m_poTexContinents = getARGBTexture( m_poIrrBase->m_poDriver, strFileName.c_str() );
	vx_assert( m_poTexContinents );
	return 0;
}


//------------------------------------------------------------------------------
//! override EntBase
//! hande collision with another object
//! return non zero if caller should not process any more contact points
RCODE   EntEarth::HandleCollision( EntBase * poOtherEntity, const btPersistentManifold * poContactManifold, float f32NormalScale )
{
	if( 300 > (m_poIrrBase->m_u32GameTimeMs - poOtherEntity->m_u32LastCollisionTimeMs) )
	{
		// physics has multiple hits for one impact
		// dont do another impact damage 
		return 0;
	}
	switch( poOtherEntity->m_eEntType )
	{
	case eEntityTypeCometFire:
		log_msg( 0, "Collision Earth <-> Comet Fire\n" );
		break;
	case eEntityTypeCometIce:
		log_msg( 0, "Collision Earth <-> Comet Ice\n" );
		break;
	case eEntityTypeAsteroidRed:
		log_msg( 0, "Collision Earth <-> Asteroid Red\n" );
		break;
	case eEntityTypeAsteroidBlue:
		log_msg( 0, "Collision Earth <-> Asteroid Blue\n" );
		break;
	default:
		log_msg( 0, "Collision Earth <-> UNKOWN\n" );
		return 0;
	}
	// there are often multiple collisions with same object so only add if not allready listed
	for( U32 i = 0; i < m_apoEntColliding.size(); i++ )
	{
		if( m_apoEntColliding[i] == poOtherEntity )
		{
			// allready in list
			return 0;
		}
	}
		//! set position of last collision	
	poOtherEntity->SetLastCollisionPosition( poOtherEntity->GetIrrPosition() );
	poOtherEntity->m_u32LastCollisionTimeMs = m_poIrrBase->m_u32GameTimeMs;

	m_apoEntColliding.push_back( poOtherEntity ); // entities earth collided with


	return 0;
}

//------------------------------------------------------------------------------
//! override EntBase
//! process before frame is rendered 
void   EntEarth::BeginFrame( void )
{
	EntBase::BeginFrame();
	// clear out any entity collisions from last frame
	m_apoEntColliding.clear(); 
}

//------------------------------------------------------------------------------
//! override EntBase
//! update
void   EntEarth::Update( U32 u32FrameTimeMs )
{
	EntBase::Update( u32FrameTimeMs );
		if( m_apoEntColliding.size() > 1 )
		{
			int iCnt = m_apoEntColliding.size();
		}
	for( U32 i = 0; i < m_apoEntColliding.size(); i++ )
	{
		// create craters etc for each object that hit earth
		m_poIrrBase->HandleCollision( this, m_apoEntColliding[i] );
		int iTotalPixels;
		int iPixelsDestroyed;

		int iPercentGroundDamage = MakeImpactDamage( m_apoEntColliding[i], iTotalPixels, iPixelsDestroyed );
		//m_apoEntColliding[i]->ResetToStartingPosition();
		m_poIrrBase->m_bNeedProgressUpdate = true;
		irr::core::vector3df v3fPos = m_apoEntColliding[i]->GetLastCollisionPosition();
		if( iPercentGroundDamage > 50 )
		{
			if( ( m_apoEntColliding[i]->m_eEntType == eEntityTypeAsteroidRed ) ||
				( m_apoEntColliding[i]->m_eEntType == eEntityTypeAsteroidBlue ) )
			{
				m_poIrrBase->ShowTimedMessage( irr::core::vector3df( v3fPos.X + 50.0f, v3fPos.Y, v3fPos.Z ), "BONUS 200 POINTS", 3 );
			}
			g_oSndMgr.SfxPlay( "explode1.ogg" );
		}
		else
		{
			if( ( m_apoEntColliding[i]->m_eEntType == eEntityTypeAsteroidRed ) ||
				( m_apoEntColliding[i]->m_eEntType == eEntityTypeAsteroidBlue ) )
			{
				irr::core::vector3df v3fPos = m_apoEntColliding[i]->GetLastCollisionPosition();
				v3fPos.X += 50;
				m_poIrrBase->ShowTimedMessage(  irr::core::vector3df( v3fPos.X + 50.0f, v3fPos.Y, v3fPos.Z ), "BONUS 50 POINTS", 3 );
			}
			g_oSndMgr.SfxPlay( "sizzel.ogg" );
		}
		m_apoEntColliding[i]->ResetToStartingPosition();
		char as8Buf[ 128 ];
		sprintf( as8Buf, "DAMAGE %d", iPixelsDestroyed );
		m_poIrrBase->ShowTimedMessage( v3fPos, as8Buf, 3, 0xffff0000 );

	}
}

//------------------------------------------------------------------------------
//! override EntBase
//! process after frame is rendered 
void   EntEarth::EndFrame( void )
{
	EntBase::EndFrame();
}

//------------------------------------------------------------------------------
//! show crater etc and determine damage done by impact
int   EntEarth::MakeImpactDamage( EntBase * poEntColliding, int& iRetTotalPixels, int& iRetPixelsDestroyed, BOOL bShowIntersectPointOnly )
{
	iRetTotalPixels = 0;
	iRetPixelsDestroyed = 0;
	int iPercentGroundDamage = 0;
	if( NULL == this->m_poMesh )
	{
		// no mesh to test against
		return iPercentGroundDamage;
	}
	// create a line from colliding entity to earth
	irr::core::line3df oLine( this->GetIrrPosition(), poEntColliding->GetLastCollisionPosition() );

	// test line to see which triangle it intersects
	irr::core::vector3df v3fTriangleIntersect; 
	irr::core::triangle3df tri; 
	// cast our scene node so we have access to mesh etc
	irr::scene::IAnimatedMeshSceneNode * poNode = (irr::scene::IAnimatedMeshSceneNode * )this->m_poSceneNode;
	irr::scene::ITriangleSelector * selector = 
		m_poIrrBase->m_poSceneMgr->createTriangleSelector( 
		m_poMesh->getMesh( (irr::s32) poNode->getFrameNr() ), this->m_poSceneNode  ); 


	//log_msg( LOG_DEBUG, "MakeImpactDamage getting collision point\n");
	irr::scene::ISceneNode * outNode; 
	irr::s32 iVertexIdx = 0;
	if( m_poIrrBase->m_poSceneMgr->getSceneCollisionManager()->getCollisionPoint( oLine, selector, v3fTriangleIntersect, tri, outNode, &iVertexIdx ) ) 
	{ 

		// the vertex index of first point of triangle is actually the triangle index * 3
		iVertexIdx *= 3;

		// show point of intersection
		//m_poPointBillboard->setPosition( v3fTriangleIntersect );

		// draw the triangle we collided with
		// setup a material we can draw with
		//irr::video::SMaterial material; 
		//material.Lighting = false; 
		//m_poIrrBase->m_poDriver->setMaterial(material); 
		//m_poIrrBase->m_poDriver->setTransform( irr::video::ETS_WORLD, irr::core::matrix4() ); 
		//m_poIrrBase->m_poDriver->draw3DTriangle(tri, irr::video::SColor(255,9,255,0)); 

//		if( bShowIntersectPointOnly )
//		{
			// done .. 
//			return 0;
//		}


		//determine where on texture the point is using the uv coords

		// getCollisionPoint does not tell the uv coords of the triangle so we gota do
		// a whole bunch of hack crap
		BOOL bFoundTriangle = false;

		irr::core::vector2df v2fUvCoordsA;
		irr::core::vector2df v2fUvCoordsB;
		irr::core::vector2df v2fUvCoordsC;

		irr::core::vector3df v3fTriPointA;
		irr::core::vector3df v3fTriPointB;
		irr::core::vector3df v3fTriPointC;

		//log_msg( LOG_DEBUG, "MakeImpactDamage getting mesh\n");

		// get a pointer to the mesh
		irr::scene::IMesh * poEarthMesh = m_poMesh->getMesh( (irr::s32) poNode->getFrameNr() );
		irr::scene::IMeshBuffer* poMeshBuffer = poEarthMesh->getMeshBuffer( 0 );
		int iIndexCount = poMeshBuffer->getIndexCount();
		U16 * pau16Indexes = poMeshBuffer->getIndices();
		irr::video::E_VERTEX_TYPE eVertexType = poMeshBuffer->getVertexType();
		if( (iVertexIdx < 0) || (iVertexIdx >= iIndexCount) )
		{
			log_msg( 0, "EntEarth::MakeImpactDamage: invalid vertex index\n" );
			vx_assert( false );
			return iPercentGroundDamage;
		}

		// find the triangle and get the uv coords
		switch( eVertexType )
		{
		case irr::video::EVT_STANDARD:
			{
				irr::video::S3DVertex* vtx = (irr::video::S3DVertex*)poMeshBuffer->getVertices();
				v2fUvCoordsA = vtx[pau16Indexes[iVertexIdx + 0]].TCoords;
				v2fUvCoordsB = vtx[pau16Indexes[iVertexIdx + 1]].TCoords;
				v2fUvCoordsC = vtx[pau16Indexes[iVertexIdx + 2]].TCoords;
				v3fTriPointA = vtx[pau16Indexes[iVertexIdx + 0]].Pos;
				v3fTriPointB = vtx[pau16Indexes[iVertexIdx + 1]].Pos;
				v3fTriPointC = vtx[pau16Indexes[iVertexIdx + 2]].Pos;
			}
			break;
		case irr::video::EVT_2TCOORDS:
			{
				irr::video::S3DVertex2TCoords* vtx = (irr::video::S3DVertex2TCoords*)poMeshBuffer->getVertices();
				v2fUvCoordsA = vtx[pau16Indexes[iVertexIdx + 0]].TCoords;
				v2fUvCoordsB = vtx[pau16Indexes[iVertexIdx + 1]].TCoords;
				v2fUvCoordsC = vtx[pau16Indexes[iVertexIdx + 2]].TCoords;
				v3fTriPointA = vtx[pau16Indexes[iVertexIdx + 0]].Pos;
				v3fTriPointB = vtx[pau16Indexes[iVertexIdx + 1]].Pos;
				v3fTriPointC = vtx[pau16Indexes[iVertexIdx + 2]].Pos;
			}
			break;
		case irr::video::EVT_TANGENTS:
			{
				irr::video::S3DVertexTangents* vtx = (irr::video::S3DVertexTangents*)poMeshBuffer->getVertices();
				v2fUvCoordsA = vtx[pau16Indexes[iVertexIdx + 0]].TCoords;
				v2fUvCoordsB = vtx[pau16Indexes[iVertexIdx + 1]].TCoords;
				v2fUvCoordsC = vtx[pau16Indexes[iVertexIdx + 2]].TCoords;
				v3fTriPointA = vtx[pau16Indexes[iVertexIdx + 0]].Pos;
				v3fTriPointB = vtx[pau16Indexes[iVertexIdx + 1]].Pos;
				v3fTriPointC = vtx[pau16Indexes[iVertexIdx + 2]].Pos;
			}
			break;
		default:
			log_msg( 0, "EntEarth::MakeImpactDamage: Invalid vertex\n" );
			vx_assert( false );
		}
		irr::core::vector2df v2fImpactUvCoord; // uv coord of point of impact
		v2fImpactUvCoord = v2fUvCoordsA;

		//log_msg( LOG_DEBUG, "MakeImpactDamage getting texture\n");

		// we have the triangle and uv coords now we want the exact pixel coord in the texture of point of impact
		// get texture
		irr::video::ITexture * poTexture = m_poSceneNode->getMaterial(0).getTexture(0);
		if( NULL == poTexture )
		{
			log_msg( 0, "EntEarth::MakeImpactDamage: Could Not find texture\n" );
			return iPercentGroundDamage;
		}
		// get texture size
		irr::core::dimension2d<irr::u32> oTextureSize =  poTexture->getSize();
		// get pixel coord of impact
		int iXPos = (int)(oTextureSize.Width * v2fImpactUvCoord.X );
		int iYPos = (int)(oTextureSize.Height * v2fImpactUvCoord.Y );

		
		// get crater texture
		irr::video::ITexture * poCraterTexture = m_apoTexCraters[m_iDefautCraterIdx];
		if( poEntColliding->GetPowerLevel() > 0 )
		{
			poCraterTexture = m_apoTexCraters[m_iDefautCraterIdx-1];
		}

		irr::core::dimension2d<irr::u32> oSrcTextureSize =  poCraterTexture->getSize();

		//log_msg( LOG_DEBUG, "MakeImpactDamage drawing crater\n");
		// draw crater but exclude drawing in the ocean by using the exclude low and exclude high colors
		//					red		green	blue
		// exclude low		0		10		30
		// exclude high		16		70		130
		iPercentGroundDamage = DoCraterDamage(	iRetTotalPixels,
												iRetPixelsDestroyed,
												poCraterTexture,
												iXPos - (oSrcTextureSize.Width >> 1),
												iYPos - (oSrcTextureSize.Height >> 1),
												poTexture,
												true,
												0x000A1E,
												0x104682 );
		//log_msg( LOG_DEBUG, "MakeImpactDamage done\n");
	}
	// done with selector
	// the irrlicht rule is if the function that gets the object begins with create then you must delete it
	// else you just call ->drop()
	delete selector;
	return iPercentGroundDamage;
}
//------------------------------------------------------------------------------
//! returns the percent of earth considered destroyed
float EntEarth::GetPercentOfEarthDestroyed( void )
{
	int iPixelsDestroyed = 0;
	int iPixelsLive = 0;
	// get texture
	irr::video::ITexture * poTexture = m_poSceneNode->getMaterial(0).getTexture(0);
	if( NULL == poTexture )
	{
		log_msg( 0, "EntEarth::PercentOfEarthDestroyed: Could Not find texture\n" );
		return 0.0f;
	}
	// get texture size
	irr::core::dimension2d<irr::u32> oTextureSize =  poTexture->getSize();

	U32 * pu32SrcPixels = (U32 *)poTexture->lock( irr::video::ETLM_READ_ONLY );

	// colors considered ocean
	//					red		green	blue
	// ocean low		0		10		30
	// ocean high		16		70		130

	// colors considered antartica
	//					red		green	blue
	// above			250		250		250

	// colors considered destroyed earth
	//					red		green	blue
	// below			60		60		60


	
	// for speed
	int iPixelCount = (int)(oTextureSize.Width * oTextureSize.Height);
	U8 u8Red;
	U8 u8Green;
	U8 u8Blue;
	U32 u32Color;
	for( int i = 0; i < iPixelCount; i++ )
	{
		u32Color = (*pu32SrcPixels) & 0xffffff;
		pu32SrcPixels++;
		u8Red = u32Color >> 16;
		u8Green = (u32Color & 0xff00) >> 8;
		u8Blue = u32Color & 0xff;
		if( ( u8Red > 250 ) &&
			( u8Green > 250 ) &&
			( u8Blue > 250 ) )
		{
			// white part of antartica
			continue;
		}
		if( ( u8Green >= 10 ) &&
			( u8Blue >= 30 ) &&
			( u8Red <= 16 ) &&
			( u8Green <= 70 ) &&
			( u8Blue <= 130 ) )
		{
			// ocean
			continue;
		}
		if( ( u8Red <= 60 ) &&
			( u8Green <= 60 ) &&
			( u8Blue <= 60 ) )
		{
			// this part of world was destroyed
			iPixelsDestroyed++;
		}
		else
		{
			// this part of world still alive
			iPixelsLive++;
		}
	}
	poTexture->unlock();
	// return the calculated percentage
	return ( iPixelsDestroyed * 100) / (iPixelsDestroyed + iPixelsLive);
}
//------------------------------------------------------------------------------
//! blit image from one texture into another ( both textures must be 32bit format )
//! return percent pixels changed
int EntEarth::DoCraterDamage(	int&					iRetTotalPixels,	// total pixels in texture					
								int&					iRetPixelsDestroyed,// number of pixels changed
								irr::video::ITexture *	poSrcTexture,		// texture to use as source image ( must be A8R8G8B8 fromat )
								U32						u32DestXPos,		// left pixel of destination image to blit to
								U32						u32DestYPos,		// top pixel of destination image to blit to
								irr::video::ITexture *	poDestTexture,		// texture to blit onto ( must be A8R8G8B8 fromat )
								BOOL					bWrap,				// if true then if blit goes past edge of destination image then wrap to other side
								U32						u33ExcludeLowColor, // if u33ExcludeLowColor != u33ExcludeHighColor then exclude copying to dest if
								U32						u33ExcludeHighColor )// color is not between u33ExcludeLowColor and u33ExcludeHighColor
{
	iRetTotalPixels = 0;
	iRetPixelsDestroyed = 0;
	int iPixelsChanged = 0;
	BOOL bHasExclusionColors = (u33ExcludeLowColor == u33ExcludeHighColor)?false:true;
	const irr::core::dimension2d<irr::u32> oDestSize = poDestTexture->getSize();
	U32 u32DestWidth = oDestSize.Width;
	U32 u32DestHeight = oDestSize.Height;
	if( ( u32DestXPos >= u32DestWidth ) || ( u32DestYPos >= u32DestHeight ) )
	{
		log_msg( 1, "BlitTextureOnTexture: destination coords not even on dest texture\n" );
		return iPixelsChanged;
	}


	const irr::core::dimension2d<irr::u32> oSrcSize = poSrcTexture->getSize();
	U32 u32SrcWidth = oSrcSize.Width;
	U32 u32SrcHeight = oSrcSize.Height;
	iRetTotalPixels = (int)( u32SrcWidth * u32SrcHeight );

	U32 * pu32SrcPixels = (U32 *)poSrcTexture->lock( irr::video::ETLM_READ_ONLY );
	U32 u32SrcIdx = 0;
	U32 * pu32DestPixels = (U32 *)poDestTexture->lock();
	U32 * pu32ContinetsPixels = (U32 *)m_poTexContinents->lock();
	//memset( pu32DestPixels, 0x7f, sizeof( U32 ) *  u32DestWidth * u32DestHeight );
	for( U32 u32SrcRow = 0; u32SrcRow < u32SrcHeight; u32SrcRow++ )
	{
		// for each src row
		// calculate destination row
		U32 u32DestRowIdx = u32SrcRow + u32DestYPos;
		if( u32DestRowIdx >= u32DestHeight )
		{
			// this row is past end of bitmap.. should we wrap ?
			if( false == bWrap )
			{
				// skip row
				continue;
			}
			else
			{
				u32DestRowIdx = u32DestRowIdx - u32DestHeight;
			}
		}
		U32 u32DestColIdx = u32DestXPos;


		for( U32 u32SrcCol = 0; u32SrcCol < u32SrcWidth; u32SrcCol++ )
		{
			U32 u32SrcColor = pu32SrcPixels[ u32SrcIdx ];
			u32SrcIdx++;

			if( u32DestColIdx >= u32DestWidth )
			{
				// this column is past end of bitmap.. should we wrap ?
				if( false == bWrap )
				{
					// skip rest of row
					break;
				}
				else
				{
					u32DestColIdx = u32DestColIdx - u32DestWidth;
				}
			}
			U32 u32DestArrayIdx = ( u32DestRowIdx *  u32DestWidth ) + u32DestColIdx;
			u32DestColIdx++;
			U32 u32DestColor = pu32DestPixels[ u32DestArrayIdx ];
			
			if( bHasExclusionColors )
			{
				// check if is a color we dont want to copy to
				if( (( u32DestColor & 0xff ) >= (u33ExcludeLowColor & 0xff )) &&
					(( u32DestColor & 0xff00 ) >= (u33ExcludeLowColor & 0xff00 )) &&
					(( u32DestColor & 0xff0000 ) >= (u33ExcludeLowColor & 0xff0000 )) &&
					(( u32DestColor & 0xff ) <=  (u33ExcludeHighColor & 0xff )) &&
					(( u32DestColor & 0xff00 ) <= (u33ExcludeHighColor & 0xff00 )) &&
					(( u32DestColor & 0xff0000 ) <= (u33ExcludeHighColor & 0xff0000 )) )
				{
					//color is in the exclusion range
					continue;
				}
			}
			// not excluded so blend 
			pu32DestPixels[ u32DestArrayIdx ] = VxBlendColors( u32SrcColor, pu32DestPixels[ u32DestArrayIdx ] );
			iRetPixelsDestroyed++;
			// see if did some continent damage
			//if( pu32ContinetsPixels[ u32DestArrayIdx ] )
			//{
			//	switch( pu32ContinetsPixels[ u32DestArrayIdx ] )
			//	{
			//	}
			//	pu32ContinetsPixels[ u32DestArrayIdx ] = 0;
			//}
			
			//pu32DestPixels[ u32DestArrayIdx ] = pu32DestPixels[ u32DestArrayIdx ] & 0x133f3f3f;
			//if( 0 != ( u32SrcColor & 0xff000000 ) )
			//{
			//	pu32DestPixels[ u32DestArrayIdx ] = u32SrcColor;
			//}
		}
	}
	poSrcTexture->unlock();
	poDestTexture->unlock();
	m_poTexContinents->unlock();
	return ( iRetPixelsDestroyed * 100 )/( iRetTotalPixels );
}
//------------------------------------------------------------------------------
//! called once per second
void EntEarth::OncePerSecond( void )
{
	if( this->GetPowerLevel() > 0 )
	{
		vx_assert( this->m_s32PowerUpTTL )
		this->m_s32PowerUpTTL--;
		if( 0 == this->m_s32PowerUpTTL )
		{
			m_s32PowerLevel = 0;
			OnPowerLevelDown();
		}
	}
}
//------------------------------------------------------------------------------
//! handle changes when power level goes up
void EntEarth::OnPowerLevelUp( S32 s32PowerLevel, S32 s32PowerUpTTL )
{
	m_s32PowerLevel = s32PowerLevel;
	this->m_s32PowerUpTTL = s32PowerUpTTL;


}
//------------------------------------------------------------------------------
//! handle changes when power level goes down
void EntEarth::OnPowerLevelDown( void )
{

}


